<?php
/**
 * JurnalPort client class file 
 *
 * @package JurnalPort
 */

require_once 'Encryption.php';

/**
 * JurnalPort client class
 * 
 * @package JurnalPort
 * @author Jansen Price <jansen.price@gmail.com>
 * @version $Id$
 */
class JurnalPortClient extends Qi_Console_Client
{
    /**
     * Version
     *
     * @var string
     */
    const VERSION = '1.0.3';

    /**
     * Editor
     * 
     * @var string
     */
    protected $_editor = '';

    /**
     * Home directory
     * 
     * @var string
     */
    protected $_homeDir = '';

    /**
     * Jurnal port server api URL
     * 
     * @var string
     */
    protected $_jurnalPortApiUrl = 
        'http://localhost/jurnalportserver/web/api/';

    /**
     * Initialize this object
     * 
     * @return void
     */
    public function init()
    {
        if (isset($_SERVER['EDITOR'])) {
            $this->_editor = $_SERVER['EDITOR'];
        } else {
            $this->_editor = '/usr/bin/vim';
        }

        if (isset($_SERVER['HOME'])) {
            $this->_homeDir = $_SERVER['HOME'];
        }
    }

    /**
     * Execute the client
     * 
     * @return void
     */
    public function execute()
    {
        if ($this->_args->help) {
            $this->displayHelp();
            $this->_safeExit(0);
        }

        if ($this->_args->g) {
            $this->_editor = 'gvim';
        }

        if ($this->_args->version) {
            $this->_displayMessage(
                'Jurnalport version ' . self::VERSION, true, 8
            );
            $this->_safeExit(0);
        }

        switch ($this->_args->action) {
        case 'last':
            echo $this->retrieve(1);
            break;
        case 'list':
        case 'read':
            $limit = $this->_getLimit();
            echo $this->retrieve($limit);
            break;
        case 'headings':
            $limit = $this->_getLimit();
            echo $this->retrieveHeadings($limit);
            break;
        case 'add':
            echo $this->promptEntry();
            break;
        case 'help':
            $this->displayHelp();
            $this->_safeExit(0);
            break;
        default:
            $this->_halt('Unrecognized command `' . $this->_args->action . '\'');
            break;
        }
    }

    /**
     * Retrieve entries
     * 
     * @param int $limit Limit of entries to retrieve
     * @return string
     */
    public function retrieve($limit = 3)
    {
        $response = $this->_fetchApi('retrieve?limit=' . $limit);
        $listing  = '';
        
        $i = 0;

        foreach ($response->result as $entry) {
            $listing .= ++$i . " >> " 
                . date('l \t\h\e jS \o\f F, Y H:i', $entry->date)
                . ' [' . $entry->id . ']'
                . "\n" . str_repeat('-', 79) . "\n"
                . $entry->text . "\n\n";
        }

        return $listing;
    }

    /**
     * Retrieve headings
     * 
     * @param int $limit
     * @return void
     */
    public function retrieveHeadings($limit = 3)
    {
        $response = $this->_fetchApi('retrieveHeadings?limit=' . $limit);
        $listing  = '';

        $i = 0;

        foreach ($response->result as $entry) {
            $listing .= ++$i . " >> " 
                . date('Y-m-d H:i', $entry->date)
                . ' [' . $entry->id . ']'
                . ' ~ ' . trim($entry->text) . "...\n";
        }

        return $listing;
    }

    /**
     * Fetch something from the API
     * 
     * @param string $request
     * @return string
     */
    protected function _fetchApi($request)
    {
        $url = $this->_jurnalPortApiUrl . $request;

        $contents = file_get_contents($url);

        $contents = Encryption::decrypt($contents);

        $response = json_decode($contents);
        return $response;
    }

    /**
     * Prompt to create and add an entry
     * 
     * @return string
     */
    public function promptEntry()
    {
        $entryFile = $this->_homeDir . DIRECTORY_SEPARATOR . ".tmp-journal";
        $cmd = $this->_editor . ' ' . $entryFile;

        echo $cmd . "\n";
        passthru($cmd);

        if (!file_exists($entryFile)) {
            return "Aborted. No journal entry written to temp file.\n";
        }

        $message = file_get_contents($entryFile);
        $message = wordwrap(trim($message), 79);
        $date    = null;

        if ($this->_args->date) {
            $date = $this->_args->date;
        }

        $result = $this->add($message, $date);

        unlink($entryFile);

        return $result;
    }

    /**
     * Add an entry
     * 
     * @param string $message Text of entry
     * @param string $date Date
     * @return string
     */
    public function add($message, $date = null)
    {
        $url = $this->_jurnalPortApiUrl . 'add';

        $post = array(
            'message' => $message,
        );

        if (null !== $date) {
            $post['date'] = $date;
        }

        $response = $this->http($url, 'POST', $post);
        $response = Encryption::decrypt($response);
        $result   = json_decode($response);

        return $result->result . "\n";
    }

    /**
     * Display help message
     *
     * @return void
     */
    public function displayHelp()
    {
        if ($this->_args->version) {
            $this->_displayMessage(
                'Jurnalport version ' . self::VERSION, true, 8
            );
        }

        $message = "Usage: jurnalport [OPTIONS] <command> [limit]\n"
            . "\n"
            . "Options:\n"
            . "  -g        Use graphical editor (gvim)\n"
            . "  --version Display version and exit\n"
            . "\n"
            . "Commands:\n"
            . "  add       Add a new entry\n"
            . "  headings  Display headings for last [limit] entries\n"
            . "  help      Display help message\n"
            . "  last      Display the last entry\n"
            . "  list      List last [limit] entries\n"
            . "  read      Alias for list\n";

        $this->_displayMessage($message);
    }

    /**
     * Get limit
     * 
     * @return int
     */
    protected function _getLimit($default = 3)
    {
        $limit = (int) $default;

        if ($this->_args->__arg2 !== null) {
            $limit = (int) $this->_args->__arg2;
        }

        if ($this->_args->limit !== null) {
            $limit = (int) $this->_args->limit;
        }

        return $limit;
    }

    /**
     * Make an HTTP request
     *
     * @param string $url Url
     * @param string $method HTTP method
     * @param array $postfields Post fields
     * @return void
     */
    public function http($url, $method, $postfields = null)
    {
        $this->http_info = array();

        $ci = curl_init();

        /* Curl settings */
        curl_setopt($ci, CURLOPT_USERAGENT, 'JurnalPort/1.0');
        curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, 2);
        curl_setopt($ci, CURLOPT_TIMEOUT, 10);
        curl_setopt($ci, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ci, CURLOPT_HTTPHEADER, array('Expect:'));
        //curl_setopt($ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader'));
        curl_setopt($ci, CURLOPT_HEADER, false);

        switch ($method) {
        case 'POST':
            curl_setopt($ci, CURLOPT_POST, true);
            if (!empty($postfields)) {
                curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields);
            }
            break;
        case 'DELETE':
            curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE');
            if (!empty($postfields)) {
                $url = "{$url}?{$postfields}";
            }
        }

        curl_setopt($ci, CURLOPT_URL, $url);

        $response = curl_exec($ci);

        $this->http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);
        $this->http_info = array_merge($this->http_info, curl_getinfo($ci));

        $this->url = $url;
        curl_close($ci);

        return $response;
    }
}
